GQuark uniforms[N_UNIFORMS];
GQuark attributes[N_ATTRIBUTES];
- GskShaderBuilder *blend_program;
+ GskShaderBuilder *shader_builder;
+
+ int blend_program_id;
guint vao_id;
gsk_gl_renderer_create_programs (GskGLRenderer *self)
{
GskShaderBuilder *builder;
- const char *vertex_preamble;
- const char *fragment_preamble;
- int vertex_id = -1, fragment_id = -1;
GError *error = NULL;
gboolean res = FALSE;
if (gdk_gl_context_get_use_es (self->context))
{
gsk_shader_builder_set_version (builder, SHADER_VERSION_GLES);
+ gsk_shader_builder_set_vertex_preamble (builder, "es2_common.vs.glsl");
+ gsk_shader_builder_set_fragment_preamble (builder, "es2_common.fs.glsl");
gsk_shader_builder_add_define (builder, "GSK_GLES", "1");
-
- vertex_preamble = "gles_common.vs.glsl";
- fragment_preamble = "gles_common.fs.glsl";
}
else if (gdk_gl_context_is_legacy (self->context))
{
gsk_shader_builder_set_version (builder, SHADER_VERSION_GL_LEGACY);
+ gsk_shader_builder_set_vertex_preamble (builder, "gl_common.vs.glsl");
+ gsk_shader_builder_set_fragment_preamble (builder, "gl_common.fs.glsl");
gsk_shader_builder_add_define (builder, "GSK_LEGACY", "1");
-
- vertex_preamble = "gl_common.vs.glsl";
- fragment_preamble = "gl_common.fs.glsl";
}
else
{
gsk_shader_builder_set_version (builder, SHADER_VERSION_GL3);
+ gsk_shader_builder_set_vertex_preamble (builder, "gl3_common.vs.glsl");
+ gsk_shader_builder_set_fragment_preamble (builder, "gl3_common.fs.glsl");
gsk_shader_builder_add_define (builder, "GSK_GL3", "1");
-
- vertex_preamble = "gl3_common.vs.glsl";
- fragment_preamble = "gl3_common.fs.glsl";
}
#ifdef G_ENABLE_DEBUG
gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1");
#endif
- vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
- vertex_preamble,
- "blend.vs.glsl",
- &error);
- if (error != NULL)
- {
- g_critical ("Unable to compile vertex shader: %s", error->message);
- g_error_free (error);
- goto out;
- }
-
- fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
- fragment_preamble,
- "blend.fs.glsl",
- &error);
- if (error != NULL)
- {
- g_critical ("Unable to compile fragment shader: %s", error->message);
- g_error_free (error);
- goto out;
- }
-
- gsk_shader_builder_create_program (builder, vertex_id, fragment_id, &error);
+ self->blend_program_id =
+ gsk_shader_builder_create_program (builder, "blend.vs.glsl", "blend.fs.glsl", &error);
if (error != NULL)
{
g_critical ("Unable to create program: %s", error->message);
g_error_free (error);
+ g_object_unref (builder);
goto out;
}
- self->blend_program = g_object_ref (builder);
+ self->shader_builder = builder;
res = TRUE;
out:
- g_object_unref (builder);
-
- if (vertex_id > 0)
- glDeleteShader (vertex_id);
- if (fragment_id > 0)
- glDeleteShader (fragment_id);
-
return res;
}
static void
gsk_gl_renderer_destroy_programs (GskGLRenderer *self)
{
- if (self->blend_program != NULL)
- {
- int program_id = gsk_shader_builder_get_program (self->blend_program);
-
- glDeleteProgram (program_id);
-
- g_clear_object (&self->blend_program);
- }
+ g_clear_object (&self->shader_builder);
}
static gboolean
gdk_gl_context_make_current (self->context);
GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
- gsk_gl_renderer_create_buffers (self);
if (!gsk_gl_renderer_create_programs (self))
return FALSE;
+ gsk_gl_renderer_create_buffers (self);
+
return TRUE;
}
graphene_rect_t bounds;
GskRenderNode *child;
RenderItem item;
+ int program_id;
if (gsk_render_node_is_hidden (node))
{
item.render_data.vao_id = self->vao_id;
item.render_data.buffer_id = 0;
- item.render_data.program_id = gsk_shader_builder_get_program (self->blend_program);
+ program_id = self->blend_program_id;
+ item.render_data.program_id = program_id;
item.render_data.map_location =
- gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[MAP]);
+ gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MAP]);
item.render_data.parentMap_location =
- gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[PARENT_MAP]);
+ gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[PARENT_MAP]);
item.render_data.mvp_location =
- gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[MVP]);
+ gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MVP]);
item.render_data.alpha_location =
- gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[ALPHA]);
+ gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[ALPHA]);
item.render_data.blendMode_location =
- gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[BLEND_MODE]);
+ gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[BLEND_MODE]);
item.render_data.position_location =
- gsk_shader_builder_get_attribute_location (self->blend_program, self->attributes[POSITION]);
+ gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[POSITION]);
item.render_data.uv_location =
- gsk_shader_builder_get_attribute_location (self->blend_program, self->attributes[UV]);
+ gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[UV]);
if (parent != NULL)
item.parent_data = &(parent->render_data);
#include <gdk/gdk.h>
#include <epoxy/gl.h>
+typedef struct {
+ int program_id;
+
+ GHashTable *uniform_locations;
+ GHashTable *attribute_locations;
+} ShaderProgram;
+
struct _GskShaderBuilder
{
GObject parent_instance;
char *resource_base_path;
+ char *vertex_preamble;
+ char *fragment_preamble;
int version;
- int program_id;
-
GPtrArray *defines;
GPtrArray *uniforms;
GPtrArray *attributes;
- GHashTable *uniform_locations;
- GHashTable *attribute_locations;
+ GHashTable *programs;
};
G_DEFINE_TYPE (GskShaderBuilder, gsk_shader_builder, G_TYPE_OBJECT)
+static void
+shader_program_free (gpointer data)
+{
+ ShaderProgram *p = data;
+
+ g_clear_pointer (&p->uniform_locations, g_hash_table_unref);
+ g_clear_pointer (&p->attribute_locations, g_hash_table_unref);
+
+ glDeleteProgram (p->program_id);
+
+ g_slice_free (ShaderProgram, data);
+}
+
+static ShaderProgram *
+shader_program_new (int program_id)
+{
+ ShaderProgram *p = g_slice_new (ShaderProgram);
+
+ p->program_id = program_id;
+
+ p->uniform_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+ p->attribute_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ return p;
+}
+
static void
gsk_shader_builder_finalize (GObject *gobject)
{
g_clear_pointer (&self->uniforms, g_ptr_array_unref);
g_clear_pointer (&self->attributes, g_ptr_array_unref);
- g_clear_pointer (&self->uniform_locations, g_hash_table_unref);
- g_clear_pointer (&self->attribute_locations, g_hash_table_unref);
+ g_clear_pointer (&self->programs, g_hash_table_unref);
G_OBJECT_CLASS (gsk_shader_builder_parent_class)->finalize (gobject);
}
self->uniforms = g_ptr_array_new_with_free_func (g_free);
self->attributes = g_ptr_array_new_with_free_func (g_free);
- self->uniform_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
- self->attribute_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+ self->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL,
+ shader_program_free);
}
GskShaderBuilder *
builder->resource_base_path = g_strdup (base_path);
}
+void
+gsk_shader_builder_set_vertex_preamble (GskShaderBuilder *builder,
+ const char *vertex_preamble)
+{
+ g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
+
+ g_free (builder->vertex_preamble);
+ builder->vertex_preamble = g_strdup (vertex_preamble);
+}
+
+void
+gsk_shader_builder_set_fragment_preamble (GskShaderBuilder *builder,
+ const char *fragment_preamble)
+{
+ g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
+
+ g_free (builder->fragment_preamble);
+ builder->fragment_preamble = g_strdup (fragment_preamble);
+}
+
void
gsk_shader_builder_set_version (GskShaderBuilder *builder,
int version)
return TRUE;
}
-int
+static int
gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
int shader_type,
const char *shader_preamble,
int status;
int i;
- g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
- g_return_val_if_fail (shader_source != NULL, -1);
-
code = g_string_new (NULL);
if (builder->version > 0)
static void
gsk_shader_builder_cache_uniforms (GskShaderBuilder *builder,
- int program_id)
+ ShaderProgram *program)
{
int i;
for (i = 0; i < builder->uniforms->len; i++)
{
const char *uniform = g_ptr_array_index (builder->uniforms, i);
- int loc = glGetUniformLocation (program_id, uniform);
+ int loc = glGetUniformLocation (program->program_id, uniform);
- g_hash_table_insert (builder->uniform_locations,
+ g_hash_table_insert (program->uniform_locations,
GINT_TO_POINTER (g_quark_from_string (uniform)),
GINT_TO_POINTER (loc));
}
static void
gsk_shader_builder_cache_attributes (GskShaderBuilder *builder,
- int program_id)
+ ShaderProgram *program)
{
int i;
for (i = 0; i < builder->attributes->len; i++)
{
const char *attribute = g_ptr_array_index (builder->attributes, i);
- int loc = glGetAttribLocation (program_id, attribute);
+ int loc = glGetAttribLocation (program->program_id, attribute);
- g_hash_table_insert (builder->attribute_locations,
+ g_hash_table_insert (program->attribute_locations,
GINT_TO_POINTER (g_quark_from_string (attribute)),
GINT_TO_POINTER (loc));
}
int
gsk_shader_builder_create_program (GskShaderBuilder *builder,
- int vertex_id,
- int fragment_id,
+ const char *vertex_shader,
+ const char *fragment_shader,
GError **error)
{
+ ShaderProgram *program;
+ int vertex_id, fragment_id;
int program_id;
int status;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
- g_return_val_if_fail (vertex_id > 0, -1);
- g_return_val_if_fail (fragment_id > 0, -1);
+ g_return_val_if_fail (vertex_shader != NULL, -1);
+ g_return_val_if_fail (fragment_shader != NULL, -1);
+
+ vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
+ builder->vertex_preamble,
+ vertex_shader,
+ error);
+ if (vertex_id < 0)
+ return -1;
+
+ fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
+ builder->fragment_preamble,
+ fragment_shader,
+ error);
+ if (fragment_id < 0)
+ {
+ glDeleteShader (vertex_id);
+ return -1;
+ }
program_id = glCreateProgram ();
glAttachShader (program_id, vertex_id);
goto out;
}
- gsk_shader_builder_cache_uniforms (builder, program_id);
- gsk_shader_builder_cache_attributes (builder, program_id);
+ program = shader_program_new (program_id);
+ gsk_shader_builder_cache_uniforms (builder, program);
+ gsk_shader_builder_cache_attributes (builder, program);
- builder->program_id = program_id;
+ g_hash_table_insert (builder->programs, GINT_TO_POINTER (program_id), program);
#ifdef G_ENABLE_DEBUG
if (GSK_DEBUG_CHECK (OPENGL))
GHashTableIter iter;
gpointer name_p, location_p;
- g_hash_table_iter_init (&iter, builder->uniform_locations);
+ g_hash_table_iter_init (&iter, program->uniform_locations);
while (g_hash_table_iter_next (&iter, &name_p, &location_p))
{
g_print ("Uniform '%s' - location: %d\n",
GPOINTER_TO_INT (location_p));
}
- g_hash_table_iter_init (&iter, builder->attribute_locations);
+ g_hash_table_iter_init (&iter, program->attribute_locations);
while (g_hash_table_iter_next (&iter, &name_p, &location_p))
{
g_print ("Attribute '%s' - location: %d\n",
#endif
out:
- glDetachShader (program_id, vertex_id);
- glDetachShader (program_id, fragment_id);
+ if (vertex_id > 0)
+ {
+ glDetachShader (program_id, vertex_id);
+ glDeleteShader (vertex_id);
+ }
+
+ if (fragment_id > 0)
+ {
+ glDetachShader (program_id, fragment_id);
+ glDeleteShader (fragment_id);
+ }
return program_id;
}
int
gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
+ int program_id,
GQuark uniform_quark)
{
+ ShaderProgram *p = NULL;
gpointer loc_p = NULL;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
+ g_return_val_if_fail (program_id >= 0, -1);
- if (builder->program_id < 0)
+ if (builder->uniforms->len == 0)
return -1;
- if (builder->uniforms->len == 0)
+ p = g_hash_table_lookup (builder->programs, GINT_TO_POINTER (program_id));
+ if (p == NULL)
return -1;
- if (g_hash_table_lookup_extended (builder->uniform_locations, GINT_TO_POINTER (uniform_quark), NULL, &loc_p))
+ if (g_hash_table_lookup_extended (p->uniform_locations, GINT_TO_POINTER (uniform_quark), NULL, &loc_p))
return GPOINTER_TO_INT (loc_p);
return -1;
int
gsk_shader_builder_get_attribute_location (GskShaderBuilder *builder,
+ int program_id,
GQuark attribute_quark)
{
+ ShaderProgram *p = NULL;
gpointer loc_p = NULL;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
+ g_return_val_if_fail (program_id >= 0, -1);
- if (builder->program_id < 0)
+ if (builder->attributes->len == 0)
return -1;
- if (builder->attributes->len == 0)
+ p = g_hash_table_lookup (builder->programs, GINT_TO_POINTER (program_id));
+ if (p == NULL)
return -1;
- if (g_hash_table_lookup_extended (builder->attribute_locations, GINT_TO_POINTER (attribute_quark), NULL, &loc_p))
+ if (g_hash_table_lookup_extended (p->attribute_locations, GINT_TO_POINTER (attribute_quark), NULL, &loc_p))
return GPOINTER_TO_INT (loc_p);
return -1;
}
-
-int
-gsk_shader_builder_get_program (GskShaderBuilder *builder)
-{
- g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
-
- return builder->program_id;
-}